/**
主要回顾：多态

多态：一个对象具备多种形态——父类的引用类型变量指向子类的对象；接口的引用类型变量指向接口实现类的对象。
（抽象指向具体）

    1.当父类与子类存在同名变量时，访问父类的变量
    2.当父类与子类存在同名非静态函数时，访问子类成员函数
    3.当父类与子类存在同名静态函数时，访问父类成员函数
    4.不能访问子类特有的成员。
    
多态情况下：
    子父类存在同名成员时，访问的都是父类的成员，只有在同名非静态函数时访问子类成员。
    
编译看左边，运行不一定看右边
    编译看左边：java 编译器在编译时，先检查引用类型所属的类是否具备指定的成员，如果没有，则报错
    运行不一定看右边：非静态函数
    
多态作用：（提高了代码的拓展性）
    1.多态用于形参类型的时，可以接收更多类型的数据
    2.多态用于返回值类型时，可以返回更多类型的数据
*/

abstract class Myshape{
    public abstract void getArea();
    public abstract void getGirth();
}

class Circle extends Myshape{
    
    public double r;
    public static final double PI = 3.14;
    
    public Circle(double r){
        this.r = r;     
    }
    
    public void getArea(){
        System.out.println("Circle's area is: " + PI*r*r);
    }
    
    public void getGirth(){
        System.out.println("Circle's girth is: " + 2*PI*r);
    }
}

class Rect extends Myshape{
    public int width;
    public int length;
    
    public Rect(int w, int l){
        this.width = w;
        this.length = l;
    }
    
    public void getArea(){
        System.out.println("Rect's area is: " + width * length);
    }
    
    public void getGirth(){
        System.out.println("Rect's girth is: " + 2*(width + length));
    }
}

class LearnPolymorphism {
    public static void main(String[] args) {
        
        /*多态用于形参类型的时，可以接收更多类型的数据：print*/
        Circle c = new Circle(4.0);
        print(c);    //c 的类型是 Circle
        
        Rect r = new Rect(2, 3);
        print(r);    //r 的类型是 Rect
        
        /*多态用于返回值类型时，可以返回更多类型的数据：getShape*/
        Myshape m = getShape(0);
        print(m);    //m 的类型是 Circle
        
        Myshape s = getShape(1);
        print(s);    //s 的类型是 Rect
        
    }
    
    //如果不使用多态，这里只能通过方法重载的方式来满足不同的参数类型
    public static void print(Myshape s){    //本质上：Myshape s = new Circle(4.0);
                                            //也就是所谓的父类引用类型变量指向子类对象
        s.getArea();
        s.getGirth();
    }
    
    //通过多态，这里既可以返回 Circle 也可以返回 Rect
    public static Myshape getShape(int shape){
        if(shape == 0){
            return new Circle(4.0);
        }else{
            return new Rect(3, 4);
        }
    }
}